import { toValue } from 'vue';
import { useState, useTimerInterval } from '@/hooks';
import loading from '@/common/loading';
import dayjs from 'dayjs';

/**
 * 处理时间范围参数
 *
 * @param {Array<Date>} dates 时间数组
 * @returns {string[]|*[]} 时间数组
 */
function handleFormatDateArray(dates) {
  const formatDate = (date) => dayjs(date).format('YYYY-MM-DD');

  if (Array.isArray(dates)) {
    const [startTime, endTime] = dates;
    return [formatDate(startTime), formatDate(endTime)];
  }
  return [];
}

/**
 * 预处理搜索参数
 *
 * @param {Object} values
 * @returns {Object} values
 */
const preHandleSearch = (values) => {
  if (values?.createTimes) {
    let [startTime, endTime] = handleFormatDateArray(values.createTimes);
    values.startTime = startTime;
    values.endTime = endTime;
    Reflect.deleteProperty(values, 'createTimes');
  }
  if (values?.updateTimes) {
    let [startTime, endTime] = handleFormatDateArray(values.updateTimes);
    values.startUpdateTime = startTime;
    values.endUpdateTime = endTime;
    Reflect.deleteProperty(values, 'updateTimes');
  }
  return values;
};

/**
 * 获取数据
 *
 * @param {Function} onAsyncFunc -- 必选 获取数据的方法
 * @param {Boolean} screen -- 可选 是否开启loading，默认为 true
 * @returns {Object} {spinning, onFetch}
 */
export function useFetch(onAsyncFunc, screen = true) {
  // 判断是否为异步函数，原型链
  if (onAsyncFunc && onAsyncFunc.prototype instanceof Function) {
    throw new TypeError('onAsyncFunc must be a function');
  }

  const [spinning, setSpinning] = useState(false);

  const onFetch = (props) => {
    screen && loading.start();
    setSpinning(true);
    return onAsyncFunc(props).finally(() => {
      screen && loading.done();
      setSpinning(false);
    });
  };

  return { spinning, onFetch };
}

/**
 * @Description: 封装获取数据的方法
 *
 * @param {Function} onAsyncFunc 必选 获取数据的方法
 * @param {any} [initialValue={}] 可选 初始化数据
 * @returns {Object} {sourceData, spinning, pagination, onFetchData, onSearchData, onPageChange, onResetData, onRefreshData}
 */
export function useFetchData(onAsyncFunc, initialValue = []) {
  // 判断是否为异步函数，原型链
  if (onAsyncFunc && onAsyncFunc.prototype instanceof Function) {
    throw new TypeError('onAsyncFunc must be a function');
  }

  const [sourceData, setSourceData] = useState(initialValue);
  const [spinning, setSpinning] = useState(false);
  const [search, setSearch] = useState({});
  const [timer, onStartTimer] = useTimerInterval();

  /**
   * 获取数据
   *
   * @param {Object} props
   * @returns void
   */
  const onFetchData = async (props = {}) => {
    setSpinning(true);
    const options = { ...toValue(search), ...props };
    const content = await onAsyncFunc(options).finally(() => setSpinning(false));
    setSourceData(content);
  };

  const onSearchData = (values) => {
    values = preHandleSearch(values);
    setSearch(values);
    onFetchData();
  };

  const onResetData = () => {
    const exist = !!Object.values(toValue(search)).filter(Boolean).length;

    if (exist === false) {
      return;
    }
    setSearch({});
    onFetchData();
  };

  const onRefreshData = (force = false) => {
    if (force === false && toValue(timer)) {
      return;
    }
    onFetchData();
    onStartTimer(10);
  };

  const clearData = () => {
    setSourceData(initialValue);
    setSearch(null);
  };

  return {
    sourceData,
    spinning,
    timer,
    onFetchData,
    onSearchData,
    onResetData,
    onRefreshData,
    clearData
  };
}

/**
 * @description 封装分页数据获取逻辑
 *
 * @param {function} onAsyncFunc -- 必选 获取数据的方法
 * @returns {Object} {sourceData, spinning, pagination, onFetchData, onSearchData, onPageChange, onResetData, onRefreshData}
 */
export function useFetchPageData(onAsyncFunc) {
  // 判断是否为异步函数，原型链
  if (onAsyncFunc && onAsyncFunc.prototype instanceof Function) {
    throw new TypeError('onAsyncFunc must be a function');
  }
  const defaultPagination = { pageNum: 1, pageSize: 20, total: 0 };
  const [sourceData, setSourceData] = useState([]);
  const [spinning, setSpinning] = useState(false);
  const [pagination, setPagination] = useState(defaultPagination);
  const [search, setSearch] = useState({});
  const [timer, onStartTimer] = useTimerInterval();

  /**
   * 获取数据
   *
   * @param {Object}  props
   * @returns {void}
   */
  const onFetchData = async (props = {}) => {
    setSpinning(true);
    const { pageNum, pageSize } = toValue(pagination);
    const options = { pageNum, pageSize, ...toValue(search), ...props };
    const { content, ...page } = await onAsyncFunc(options).finally(() => setSpinning(false));
    setSourceData(content);
    setPagination(page);
  };

  /**
   * 搜索数据
   * @param {Object} values 搜索参数
   * @param {Array} values.createTimes 时间范围
   * @param {Array} values.updateTimes 更新时间范围
   * @param {Object} values.params 其他参数
   * @returns {void}
   */
  const onSearchData = (values) => {
    if (Object.values(values).filter(Boolean).length === 0) {
      return;
    }
    setPagination(defaultPagination);
    values = preHandleSearch(values);
    setSearch(values);
    onFetchData();
  };

  /**
   * 分页切换
   *
   * @param {Number} pageNum
   * @param {Number} pageSize
   * @returns {void}
   */
  const onPageChange = (pageNum, pageSize) => {
    setPagination((v) => ({ ...v, pageNum, pageSize }));
    onFetchData();
  };

  /**
   * 重置数据
   * @returns {void}
   */
  const onResetData = () => {
    const exist = !!Object.values(toValue(search)).filter(Boolean).length;
    const { pageNum } = toValue(pagination);
    if (exist === false && pageNum === 1) {
      return;
    }
    setPagination(defaultPagination);
    setSearch({});
    onFetchData();
  };

  /**
   * 刷新数据
   * @param {Boolean} force 是否强制刷新
   * @returns {void}
   */
  const onRefreshData = (force = false) => {
    if (force === false && toValue(timer)) {
      return;
    }
    const { pageNum, pageSize, total } = toValue(pagination);
    if (pageNum > 2 && total % pageSize === 0) {
      setPagination(defaultPagination);
    }
    onFetchData();
    onStartTimer(10);
  };

  return {
    sourceData,
    spinning,
    pagination,
    timer,
    onFetchData,
    onSearchData,
    onPageChange,
    onResetData,
    onRefreshData
  };
}
